﻿using System;
using System.Collections.Generic;
using AudioStudio;
using Cinemachine;
using com.yoozoo.gta.Art.RpgScene;
using com.yoozoo.gta.Extension.UGUI.ScreenOrientationEx;
using Gameplay.PVE.Utils;
using ImageEffects;
using OWL.Rendering.HRP;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Profiling;
using Yoozoo.Core.Extensions.Engine;
using Yoozoo.Framework.Core;
using Yoozoo.Gameplay.Liberty;
using Yoozoo.Gta.Common;
using Yoozoo.HRP.Runtime;
using Yoozoo.Managers;
using Random = UnityEngine.Random;

namespace Gameplay.PVE.Survivor
{
    public class StageManager: BattleSingleton<StageManager>
    {
        public TeamGroup TeamGroup;
        private BattleMapData mapData;
        private Dictionary<int,BattleMapMonsterGroup> monsterGroupDic = new Dictionary<int, BattleMapMonsterGroup>();
        private Dictionary<int, BattleMapPoint> mapPointDic = new Dictionary<int, BattleMapPoint>();
        private Dictionary<int, BattleMapRegion> regionDic = new Dictionary<int, BattleMapRegion>();
        private Dictionary<int, MapInteractableData> interactableDic = new Dictionary<int, MapInteractableData>();
        private Dictionary<int, MapRoute> routeDic = new Dictionary<int, MapRoute>();
        private Dictionary<int, MapTruckPath> truchPathDic = new Dictionary<int, MapTruckPath>();

        private Dictionary<int,Dictionary<int,Vector3>> spawnPointGrid = new Dictionary<int,Dictionary<int,Vector3>>();

        private Quaternion spawnRotation;
        private Vector3 spawnCenter;
        private float spawnGridSize;
        private List<Vector3> spawnPoints = new List<Vector3>();
        //private Dictionary<int,MapFogData> fogDic = new Dictionary<int, MapFogData>();
        private MapFogGroup fogGroup;

        public RpgMissionConfig missionConfig;
        public RpgMissionStageConfig stageConfig;
        public Dictionary<int, RpgMissionStageConfig> stageConfigs;

        public int stageSubId = 1;
        public int stageId = 1001;

        public EnvironmentUnit environmentUnit;
        private Dictionary<ETargetTeam,EnvironmentSpawner> environmentDic = new Dictionary<ETargetTeam, EnvironmentSpawner>();

        private string mapName;

        public bool IsPause;

        private bool battleReadyToStart = false;

        private bool isBattleStart = false;

        public bool isNight = false;

        public Vector3 lightDirection;
        
        private Vector3 defaultLightDirection = (Quaternion.Euler(new Vector3(130,4.48f,200)) * Vector3.forward).normalized;
        
        public Vector4 ShadowOffset;

        private GameObject nightPositionObject;
        private GameObject nightPositionObjectBoss;

        private BattleGameObject sceneLight;
        private BattleGameObject sceneTorch;
        public bool isEnd = false;
        
        public Vector3 centerPoint;
        
		public void Initialize(int stageId,int subStageId)
        {
            Yoozoo.Gameplay.Liberty.Nodes.PlayTimeline.SkipTimeline += OnSkipTimeline;
            Yoozoo.Gameplay.Liberty.Nodes.PlayTimeline.JumpTimeline += OnJumpTimeline;
            if (stageId == 0)
            {
                stageId = 1001;
            }

            if (subStageId == 0)
            {
                subStageId = 1;
            }
            this.stageId = stageId;
            this.stageSubId = subStageId;
            stageConfigs = BattleConfigManager.Instance.GetStageConfigs(this.stageId);
            stageConfig = BattleConfigManager.Instance.GetStageConfig(this.stageId, stageSubId);
            if (stageConfig == null)
            {
                stageSubId = 1;
                stageConfig = BattleConfigManager.Instance.GetStageConfig(this.stageId, stageSubId);
            }
            InitStage();
        }

        private void InitTeam()
        {
            TeamGroup = new TeamGroup();
            TeamGroup.Initialize();
            TeamGroup.SetIsNight(isNight);
            if (isNight)
            {
                nightPositionObject.transform.SetParent(TeamGroup.Transform);
                nightPositionObject.transform.localPosition = Vector3.zero;
            }
            if (stageConfig.start_point_id != 0)
            {
                ResetTeamPosition(stageConfig.start_point_id);
            }
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.ClearBattleHeroes").Action();
            //CollisionManager.Instance.Refresh(StageManager.Instance.TeamGroup.Position);
            
            
            var heroList = SurvivorDataManager.Instance.GetHeroes();
            foreach (var item in heroList)
            {
                var unit = TeamGroup.CreateUnit(item.Value,item.Key);
                //采用布阵初始位置
                var pos = DeckManager.Instance.GetDeckPosition(item.Key);
                if (pos == BattleConstValue.DEFAULT_POINT)
                {
                    unit.Position = TeamGroup.GetTeamPosition(item.Key);
                }
                else
                {
                    unit.Position = pos;
                    unit.TargetPosition = TeamGroup.GetTeamPosition(item.Key);
                }

                unit.Forward = DeckManager.Instance.Forward;
                ResidentHandler.Inst.GetFunction("L_SurvivorManager.AddBattleHero").Action(item.Value);
            }
            if (SurvivorManager.initialHeroes.Count > 0)
            {
                for (int i = 0; i < SurvivorManager.initialHeroes.Count; i++)
                {
                    var heroId = SurvivorManager.initialHeroes[i];
                    var index = TeamGroup.Count;
                    if (heroId > 0)
                    {
                        var unit = TeamGroup.CreateUnit(heroId, -1);
                        var pos = DeckManager.Instance.GetDeckPosition(index);
                        unit.Position = TeamGroup.GetTeamPosition(index);
                        ResidentHandler.Inst.GetFunction("L_SurvivorManager.AddBattleHero").Action(heroId);
                    }
                }
            }
        }
        
        private void InitStage()
        {
            missionConfig = BattleConfigManager.Instance.GetRpgMissionConfig(stageConfig.id);
            BattlePropsManager.Instance.SetDollarRatio(missionConfig.ratio_money);
            SurvivorDataManager.Instance.dollarMax = missionConfig.drop_money_limit;
            if (SurvivorManager.useMissionHero)
            {
                ResidentHandler.Inst.GetFunction("L_SurvivorManager.InitMissionHeroes").Action(stageConfig.id);
            }

            BattleResourceManager.Instance.SetLoadCompleteCallback(PrepareBattle);
            StageReady();
            LoadMapData(stageConfig.map);
            InitEnvironment();
            SetStageCamera();
        }

        private void PrepareBattle()
        {
            BlueprintUtils.ClientReport(missionConfig.client_report_start);
            isBattleStart = false;
            if (missionConfig.is_deploy == 1)
            {
                StartDeck();
            }
            if (missionConfig.show_ui_battlestart == 1)
            {
                ShowTask();
            }
            else
            {
                CheckShowDeck();
            }
        }

        private void ShowTask()
        {
            var center = GetMapPoint(mapData.deckPointId);
            if (stageConfig.start_point_id != 0)
            {
                center = GetMapPoint(stageConfig.start_point_id);
            }

            CameraManager.Instance.StartDeck(center);
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.ShowTask").Action(stageId);
        }

        public void CheckShowDeck()
        {
            if (missionConfig.is_deploy == 1)
            {
                ShowDeck();
            }
            else
            {
                StartBattle();
            }
        }

        private void StartDeck()
        {
            //BattleResourceManager.Instance.LoadComplete(ELoadingResourceType.Timeline);
            var center = GetMapPoint(mapData.deckPointId);
            var forward = GetMapPointForward(mapData.deckPointId);
            if (stageConfig.start_point_id != 0)
            {
                center = GetMapPoint(stageConfig.start_point_id);
                forward = GetMapPointForward(stageConfig.start_point_id);
            }
            DeckManager.Instance.PrepareScene(center,forward);
            if (isNight)
            {
                nightPositionObject.transform.position = DeckManager.Instance.Center;
                ShowTorch(center,forward);
            }
            CameraManager.Instance.StartDeck(center);
        }

        private void ShowDeck()
        {
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.StartDeck").Action();

        }

        public void StartBattle()
        {
            ChangeAudioState(EAudioState.Battle);
            HideTorch();
            InitTeam();
            StageStart();
            SurvivorManager.Instance.Pause();
            battleReadyToStart = true;
        }

        private void PlayStartAnimationAndStartBattle()
        {
            if (missionConfig.show_ui_battlestart == 1)
            {
                ResidentHandler.Inst.GetFunction("L_SurvivorManager.OpenSurvivorFightStartUI").Action();
                //等待开战动画播完
                TimeManager.Instance.DelayCall(1800, callStart);
            }
            else
            {
                callStart();
            }
        }

        private void callStart()
        {
            isBattleStart = true;
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.OpenSurvivorMainUI").Action();
            if (cachedBossCameraFollow)
            {
                ShowBossCamera(cachedBossCameraFollow,cachedBossCameraForward);
                cachedBossCameraFollow = null;
            }
            else
            {
                SurvivorManager.Instance.Resume();
            }

            if (SurvivorManager.isTest)
            {
                TestManager.Instance.TestStart();
            }
        }

        public bool IsInBattle
        {
            get
            {
                return isBattleStart;
            }
        }
        
        private void InitEnvironment()
        {
            environmentUnit = ClassManager.Get<EnvironmentUnit>();
            environmentUnit.team = 1;
            environmentUnit.Initialize();
        }
        
        public Vector3 GetMapPoint(int pointId)
        {
            if (mapPointDic.TryGetValue(pointId, out var point))
            {
                return point.position;
            }
            return Vector3.zero;
        }

        public Vector3 GetMapPointForward(int pointId)
        {
            if (mapPointDic.TryGetValue(pointId, out var point))
            {
                return point.forward;
            }
            return Vector3.zero;
        }
        
        public MapInteractableData GetInteractable(int interactableId)
        {
            if (interactableDic.TryGetValue(interactableId, out var interactable))
            {
                return interactable;
            }
            BattleDebug.LogError("交互找不到 " +interactableId);
            return null;
        }

        public void Win()
        {
            if (isEnd)
            {
                return;
            }
            Pause();
            var selfHeroData = StatisticManager.Instance.GetSelfHeroList();
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.SetBattleStatisticData").Action(selfHeroData);
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.ShowBattleResult").Action(true);
            BlueprintUtils.ClientReport(missionConfig.client_report_end);
        }

        public void Lose()
        {
            if (isEnd)
            {
                return;
            }
            Pause();
            var selfHeroData = StatisticManager.Instance.GetSelfHeroList();
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.SetBattleStatisticData").Action(selfHeroData);
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.ShowBattleResult").Action(false);
            BlueprintUtils.ClientReport(missionConfig.client_report_end);
            isEnd = true;
        }
        
        public void StageToNext(int subId = 0)
        {
            if (isEnd)
            {
                return;
            }
            MissionManager.Instance.Pause();
            if (subId == 0)
            {
                stageSubId++;
            }
            else
            {
                stageSubId = subId;
            }
            if (BattleDebug.enableLog)
            {
                BattleDebug.LogError("进入下一关 " + stageSubId);  
            }
            //收集所有道具
            BattlePropsManager.Instance.PickAllProps();
            var lastStage = stageConfig;
            stageConfig = BattleConfigManager.Instance.GetStageConfig(stageId, stageSubId);
            if (stageConfig == null)
            {
                BattleEventManager.Instance.SetEnabled(false);
                BattlePropsManager.Instance.SetAutoPick(true);
                UnitManager.Instance.SetHudActive(false);
                CameraManager.Instance.SetHudCameraActive(false);
                ResidentHandler.Inst.GetFunction("L_SurvivorManager.CloseAllSurvivorUI").Action();
                if (lastStage.stage_type == 3)
                {
                    Win();
                }
                else
                {
                    //延迟2秒，然后显示结算
                    TimeManager.Instance.DelayCall(1500, () =>
                    {
                        Win();
                    });
                }
            }
            else
            {
                if (mapName != stageConfig.map)
                {
                    ResidentHandler.Inst.GetFunction("L_SurvivorManager.StartTransfer").Action<Action>(() =>
                    {
                        LoadMapData(stageConfig.map,StageStart);
                    });
                }
                else
                {
                    StageReady();
                    StageStart();
                }
            }
        }
        
        private void LoadMapData(string mapName,Action callback = null)
        {
            //先禁用单位的阻挡点
            MapManager.Instance.IsMapReady = false;
            UnitManager.Instance.DisableAgent();
            TeamGroup?.StopMove(true);
            this.mapName = mapName;
            var path = string.Format("Assets/ResourcesAssets/Pve/Survivor/Prefabs/MapData/{0}.prefab",mapName);
            BattlePoolManager.Instance.Get(path, (o) =>
            {
                o.transform.parent = SurvivorManager.Instance.Root;
                mapData = o.GetComponent<BattleMapData>();
                MapManager.Instance.LoadMap(mapData.scene);
                MapManager.Instance.RebuildNavmeshByAsset(mapData.navMeshData);
                monsterGroupDic.Clear();
                for (int i = 0; i < mapData.monsterGroup.Count; i++)
                {
                    monsterGroupDic.Add(mapData.monsterGroup[i].id,mapData.monsterGroup[i]);
                }
                mapPointDic.Clear();
                for (int i = 0; i < mapData.points.Count; i++)
                {
                    mapPointDic.Add(mapData.points[i].id,mapData.points[i]);
                }
                regionDic.Clear();
                for (int i = 0; i < mapData.regions.Count; i++)
                {
                    regionDic.Add(mapData.regions[i].id,mapData.regions[i]);
                }
                interactableDic.Clear();
                for (int i = 0; i < mapData.interactables.Count; i++)
                {
                    interactableDic.Add(mapData.interactables[i].id,mapData.interactables[i]);
                }
                BattleEventManager.Instance.SetInteractable(interactableDic);
                spawnPoints.Clear();
                for (int i = 0; i < spawnPoints.Count; i++)
                {
                    spawnPoints.Add(mapData.spawnPoints[i]);
                }

                for (int i = 0; i < mapData.routes.Count; i++)
                {
                    var route = mapData.routes[i];
                    routeDic.Add(route.id,route);
                    if (mapData.truckPath.Count > i)
                    {
                        truchPathDic.Add(route.id,mapData.truckPath[i]);
                    }
                }

                var centerPoint = Vector3.zero;
                //var width = 200;
                //var height = 200;
                var c = o.transform.Find("Center");
                if (c != null)
                {
                    centerPoint = c.position;
                    //var navmeshBakeHelper = c.gameObject.GetComponent<NavMeshBakeHelper>();
                    //if (navmeshBakeHelper != null)
                    {
                        //width = (int)navmeshBakeHelper.x;
                        //height = (int)navmeshBakeHelper.z;
                    }
                    CollisionManager.Instance.Refresh(centerPoint);
                }
                else if (stageConfig.start_point_id > 0)
                {
                    centerPoint = GetMapPoint(stageConfig.start_point_id);
                    CollisionManager.Instance.Refresh(centerPoint);
                }

                if (stageConfig.start_point_id > 0)
                {
                    CameraManager.Instance.StartDeck(GetMapPoint(stageConfig.start_point_id));
                }
                this.centerPoint = centerPoint;

                var light = o.transform.Find("Light");
                if (light != null)
                {
                    SetLightDirection(light.transform.forward);
                }
                else
                {
                    SetLightDirection(defaultLightDirection);
                }

                if (mapData.obstacles != null)
                {
                    for (int i = 0; i < mapData.obstacles.Count; i++)
                    {
                        mapData.obstacles[i].Init();
                    }
                }
                
                fogGroup = mapData.fog;
                if (fogGroup)
                {
                    fogGroup.Init(fogMask);
                    for (int i = 0; i < fogGroup.blocks.Count; i++)
                    {
                        if (fogGroup.blocks[i].defaultUnlock)
                        {
                            UnlockFog(fogGroup.blocks[i].id);
                        }
                    }
                }

                var forwardObject = mapData.transform.Find("SpawnRegionForward");
                var forward = Vector3.forward;
                if (forwardObject != null)
                {
                    forward = forwardObject.forward;
                }
                else if (stageConfig.camera_follow.Count > 0)
                {
                    forward = -new Vector3(stageConfig.camera_follow[0],stageConfig.camera_follow[1],stageConfig.camera_follow[2]);
                    forward.y = 0;
                }

                if (centerPoint != Vector3.zero && mapData.spawnPoints != null && mapData.spawnPoints.Count > 0)
                {
                    InitSpawnPoints(mapData.spawnPoints,mapData.spawnPointGridSize,centerPoint,forward);
                }
                
                callback?.Invoke();
                BattleResourceManager.Instance.LoadComplete(ELoadingResourceType.MapData);
            });
        }

        public float stageStartTime;

        public bool isInTimeline;

        public void Pause()
        {
            IsPause = true;
            TimeManager.logicTimeScale = 0;
            UnitManager.Instance.OnPause();
        }

        public void Resume()
        {
            IsPause = false;
            TimeManager.logicTimeScale = Time.timeScale;
            UnitManager.Instance.OnResume();
        }

        public void ResetTeamPosition(int pointIndex)
        {
            TeamGroup.Position = GetMapPoint(pointIndex);
            TeamGroup.Forward = GetMapPointForward(pointIndex);
            if (!DeckManager.Instance.IsInDeck)
            {
                TeamGroup.ResetPosition();
            }
            else
            {
                TeamGroup.ResetTargetPosition();
            }
            CameraManager.Instance.RefreshCamera();
            //CollisionManager.Instance.Refresh(StageManager.Instance.TeamGroup.Position);
        }

        private void StageReady()
        {
            /*if (!BattleEventManager.Instance.needLoadTimeline || SurvivorManager.skipTimeline)
            {
                BattleResourceManager.Instance.LoadComplete(ELoadingResourceType.Timeline);
            }*/
        }
        
        private void StageStart()
        {
            isEnd = false;
            BattleEventManager.Instance.SetEnabled(true);
            BattlePropsManager.Instance.SetAutoPick(false);
            if (stageConfig == null)
            {
                BattleDebug.LogError("没有找到关卡配置 " + stageId + " " + stageSubId);
                TestStart();
                return;
            }
            if (BattleDebug.enableLog)
            {
                BattleDebug.LogError("阶段开始 " + stageConfig.stage);                
            }
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.ClearAllTask").Action();
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.UpdateStageInfo").Action(stageConfig.stage);
            //如果是从布阵过来的，则使用布阵的位置
            if (stageConfig.start_point_id != 0)
            {
                ResetTeamPosition(stageConfig.start_point_id);
            }
            
            stageStartTime = TimeManager.time;

            BattleEventManager.Instance.Clear();
            for (int i = 0; i < stageConfig.events.Count; i++)
            {
                var eventId = stageConfig.events[i];
                BattleEventManager.Instance.AddEvent(eventId);
            }
            
            MissionManager.Instance.Resume();
            MissionManager.Instance.SetTasks(stageConfig.task_group);
            MapManager.Instance.OnStageChanged(stageConfig.map);
            BattleEventManager.Instance.OnStageStart(stageConfig.stage);
            //ChangeAudioState(EAudioState.Common);
            
            SetStageCamera();
            BlueprintUtils.ClientReport(stageConfig.client_report);
        }

        private void SetStageCamera()
        {
            if (stageConfig == null)
            {
                return;
            }
            //设置镜头
            if (stageConfig.camera_follow.Count > 0)
            {
                var x = stageConfig.camera_follow[0];
                var y = stageConfig.camera_follow[1];
                var z = stageConfig.camera_follow[2];
                CameraManager.Instance.SetCameraFollow(new Vector3(x, y, z));
            }
            var tarck = stageConfig.camera_track;
            if (ScreenOrientManager.GetInstance().GetScreenOrientationIsPortrait() == false)
            {
                tarck = stageConfig.camera_track_h;
            }
            if (tarck.Count > 0)
            {
                var x = tarck[0];
                var y = tarck[1];
                var z = tarck[2];
                CameraManager.Instance.SetCameraTrack(new Vector3(x, y, z));
            }

            if (stageConfig.camera_near_far.Count == 2)
            {
                var near = stageConfig.camera_near_far[0];
                var far = stageConfig.camera_near_far[1];
                CameraManager.Instance.SetCameraNearFar(near, far);
            }
            else
            {
                CameraManager.Instance.SetCameraNearFar(0.1f,150);
            }
        }

        private void TestStart()
        {
            TeamGroup.Position = GetMapPoint(2);
            TeamGroup.ResetPosition();
        }

        public void PreUpdate()
        {
            if (battleReadyToStart)
            {
                if (!BattleEventManager.Instance.HasUnfinishedBattleStartEvent() && !isInBossCamera)
                {
                    battleReadyToStart = false;
                    PlayStartAnimationAndStartBattle();
                }
            }
        }

        public override void Update()
        {
            TeamGroup?.Update();
            UpdateTimeScale();
            if (startLoadTimelineTime > 0 && Time.time - startLoadTimelineTime > 10)
            {
                //timeline加载失败，容错
                OnTimelineEnd(null);
            }
        }

        public override void LateUpdate()
        {
            TeamGroup?.LateUpdate();
        }

        public void SpawnEnemyByGroupId(int groupId)
        {
            if (monsterGroupDic.TryGetValue(groupId, out var group))
            {
                UnitManager.Instance.CreateEnemyGroup(group);
            }
        }
        
        public void SpawnSingleEnemy(int heroId,Vector3 position,Vector3 forward,EEnemyAIType aiType)
        {
            var enemy = UnitManager.Instance.CreateBattleUnit(2, heroId,position,forward);
            //enemy.aiConfig = BattleConfigManager.Instance.GetEnemyAIConfig(1);
            enemy.InitAI(aiType);
        }

        public MapTruckPath GetTruckPath(int routeId)
        {
            if (truchPathDic.TryGetValue(routeId, out var route))
            {
                return route;
            }
            BattleDebug.LogError("没有找到路径" + routeId);
            return null;
        }

        
        public MapRoute GetRoute(int routeId)
        {
            if (routeDic.TryGetValue(routeId, out var route))
            {
                return route;
            }
            BattleDebug.LogError("没有找到路径" + routeId);
            return null;
        }
        
        public BattleMapRegion GetRegion(int regionId)
        {
            if (regionDic.TryGetValue(regionId, out var region))
            {
                return region;
            }
            return null;
        }

        public void SpawnEnemyByPrefab(List<Vector2Int> enemy, int prefabId, Vector3 position,Vector3 forward,EEnemyAIType aiType)
        {
            var prefab = BattlePoolManager.Instance.Get(prefabId, (o) =>
            {
                o.transform.position = position;
                o.transform.forward = forward;
                var enemySpawn = o.GetComponent<EnemySpawnGroup>();
                if (enemySpawn)
                {
                    //尝试寻找碰撞体
                    if (enemySpawn.obstacele != null)
                    {
                        enemySpawn.obstacele.Init();
                    }
                    
                    if (!string.IsNullOrEmpty(enemySpawn.bornAnimName))
                    {
                        enemySpawn.animator.Play(enemySpawn.bornAnimName);
                    }
                    var index = 0;
                    for (int i = 0; i < enemy.Count; i++)
                    {
                        for (int j = 0; j < enemy[i].y; j++)
                        {
                            var positionId = index % enemySpawn.spawnPoints.Count;
                            var spawnPoint = enemySpawn.spawnPoints[positionId];
                            var enemyId = enemy[i].x;
                            if (spawnPoint.delayTime == 0)
                            {
                                SpawnSingleEnemy(enemyId,spawnPoint.transform.position,forward,aiType);
                            }
                            else
                            {
                                TimeManager.Instance.DelayCall((int)(spawnPoint.delayTime * 1000), () =>
                                {
                                    SpawnSingleEnemy(enemyId, spawnPoint.transform.position, forward,aiType);
                                });
                            }
                            index++;
                        }
                    }
                }
            });
        }
        
        public EnvironmentSpawner GetEnvironmentSpawner(ETargetTeam id)
        {
            if (!environmentDic.TryGetValue(id, out var spawner))
            {
                var teamMask = BattleHelper.GetTeamMaskByEnum(id);
                spawner = ClassManager.Get<EnvironmentSpawner>();
                spawner.teamMask = teamMask;
                environmentDic.Add(id, spawner);
            }
            return spawner;
        }

        private MapFogData currentFog;
        private int fogMask;
        
        public void UnlockFog(int fogId)
        {
            /*if (fogDic.TryGetValue(fogId, out var data))
            {
                BattleDebug.LogError("解锁迷雾成功 " + fogId);
                data.Show();
                if (currentFog)
                {
                    currentFog.Hide();
                }
                currentFog = data;
                UnitManager.Instance.OnFogUnlocked(fogId);
            }
            else
            {
                BattleDebug.LogError("解锁迷雾失败 " + fogId);
            }*/
            fogMask = fogMask | (1 << fogId);
            if (BattleDebug.enableLog)
            {
                BattleDebug.LogError("解锁迷雾成功 " + fogId + " " + fogMask);    
            }
            fogGroup?.UnlockFog(fogMask);
            UnitManager.Instance.OnFogUnlocked(fogId);
        }

        public bool IsFogLocked(int fogId)
        {
            if (fogId == 0)
            {
                return false;
            }

            return fogGroup.IsFogLock(fogId);
            /*if (fogDic.TryGetValue(fogId, out var data))
            {
                return data.Locked();
            }*/
            return false;
        }
        
        public void CreateEnvironmentBullet(int bulletId,Vector3 position,Vector3 forward,int fixedDamage = 0)
        {
            var config = BattleConfigManager.Instance.GetBulletConfig(bulletId);
            var bullet = BulletManager.Instance.CreateBullet(config);
            if (bullet != null)
            {
                if (BattleDebug.enableLog)
                {
                    BattleDebug.LogError("环境子弹 " + bulletId + " " + position);                
                }
                bullet.Initialize(config,GetEnvironmentSpawner(ETargetTeam.Enemy),environmentUnit);
                bullet.SetStartPosition(position);
                bullet.SetTargetPosition(position + forward.normalized * 0.01f);
                bullet.Forward = forward;
                bullet.fixedDamage = fixedDamage;
                bullet.Start();
            }
            else
            {
                BattleDebug.LogError("环境子弹找不到 " + bulletId + " " + position);
            }
        }


        private EAudioState audioState;
        public void ChangeAudioState(EAudioState state)
        {
            if (audioState != state)
            {
                if (state == EAudioState.Battle)
                {
                    AudioManager.PlayMusic("Music_RPG_Fight_01");   
                }
                else
                {
                    AudioManager.PlayMusic("Music_World");
                }
                audioState = state;
            }
        }
        
        private float changedTimeScale;
        private float timeScaleChangeStartTime;
        private float timeScaleDuration;
        private float timeScaleBackTime;
        private float timeScaleStartTime;
        public void ChangeTimeScale(float timeScale,float duration,float startTime,float backTime = 0.5f)
        {
            //Time.timeScale = timeScale;
            changedTimeScale = timeScale;
            timeScaleChangeStartTime = Time.unscaledTime;
            timeScaleStartTime = startTime;
            timeScaleDuration = duration;
            timeScaleBackTime = backTime;
        }

        public void UpdateTimeScale()
        {
            if (timeScaleChangeStartTime > 0)
            {
                var diff = Time.unscaledTime - timeScaleChangeStartTime;
                if (diff < timeScaleStartTime)
                {
                    //开始启动
                    var percent = diff / timeScaleStartTime;
                    percent = Mathf.Clamp(percent, 0, 1);
                    Time.timeScale = Mathf.Lerp(1,changedTimeScale,percent);
                }
                else if (diff < timeScaleStartTime + timeScaleDuration)
                {
                    Time.timeScale = changedTimeScale;
                }
                else
                {
                    //开始回正
                    diff = diff - timeScaleDuration - timeScaleStartTime;
                    var percent = diff / timeScaleBackTime;
                    Time.timeScale = Mathf.Lerp(changedTimeScale,1,percent);
                    if (Time.timeScale >= 1)
                    {
                        Time.timeScale = 1;
                        changedTimeScale = 0;
                        timeScaleChangeStartTime = 0;
                    }
                }
                //BattleDebug.LogError("TimeScale " + Time.timeScale);
            }
        }

        private string timelineName;
        private int timelineDelayCall;
        private double timelineDuration;
        private float startLoadTimelineTime = -1;
        
        public void PlayTimeline(string timelineName)
        {
            if (SurvivorManager.skipTimeline)
            {
                OnTimelineEnd(null);
                return;
            }
            this.timelineName = timelineName;
            //转菊花
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.ShowSmallLoading").Action();
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.SetUIMainVisible").Action(false);
            //容错
            startLoadTimelineTime = Time.time;
            BlueprintUtils.PlayTimeline(timelineName, OnTimelineEnd, (o)=>
            {
                startLoadTimelineTime = -1f;
                isInTimeline = true;
                //BattleResourceManager.Instance.LoadComplete(ELoadingResourceType.Timeline);
                Pause();
                CameraManager.Instance.OnTimelineStart();
                ResidentHandler.Inst.GetFunction("L_SurvivorManager.HideSmallLoading").Action();
                //绑定大世界刷新区域检测
                CameraManager.Instance.SetDetectorPosition(centerPoint,400);
                timelineDuration = o.duration;
                StartTimelineDelayCall((int)(timelineDuration * 1000));
            }, null,DirectorWrapMode.Hold,"","",0,null,ETimelinePathType.Survivor);
            /*BattleResourceManager.Instance.LoadPrefabByPath(path, (bool success, string assetName, object asset) =>
            {
                BattleDebug.LogError(success + " 加载Timeline完成" + path);
                ResidentHandler.Inst.GetFunction("L_SurvivorManager.HideSmallLoading").Action();
                if (success)
                {
                    var gameObject = GameObject.Instantiate(asset as GameObject);
                    gameObject.transform.SetParent(SurvivorManager.Instance.Root);
                    var director = gameObject.GetComponentInChildren<PlayableDirector>();
                    if (director)
                    {
                        director.Play();
                        CameraManager.Instance.StartTimeline(director);
                        TimeManager.Instance.DelayCall((int)(director.duration * 1000), () =>
                        {
                            GameObject.DestroyImmediate(gameObject);
                            BattleDebug.LogError("销毁Timeline" + path);
                        });
                    }
                }
            });*/
        }

        private void OnTimelineEnd(PlayableDirector director)
        {
            startLoadTimelineTime = -1;
            if (string.IsNullOrEmpty(timelineName))
            {
                return;
            }
            //CameraManager.Instance.SetDetectorPosition(BattleConstValue.DEFAULT_POINT,100);
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.SetUIMainVisible").Action(true);
            
            isInTimeline = false;
            Resume();
            MissionManager.Instance.OnTimelineComplete();
            //如果已经结束，则延迟销毁
            if (stageConfig == null)
            {
                /*TimeManager.Instance.DelayCall(500, () =>
                {
                    BlueprintUtils.StopTimeline(timelineName);
                    timelineName = null;
                });*/
            }
            else
            {
                CameraManager.Instance.OnTimelineEnd();
                BlueprintUtils.StopTimeline(timelineName);
                timelineName = null;
            }
        }

        private void StopTimelineDelayCall()
        {
            if (timelineDelayCall > 0)
            {
                TimeManager.Instance.CancelDelayCall(timelineDelayCall);
                timelineDelayCall = 0;
            }
        }

        private void StartTimelineDelayCall(int delay)
        {
            StopTimelineDelayCall();
            timelineDelayCall = TimeManager.Instance.DelayCall(delay, () =>
            {
                OnTimelineEnd(null);
            });
        }
        
        private void OnJumpTimeline(string timelineName, double jumpTime)
        {
            //OnSkipTimeline(timelineName);
            timelineDelayCall = TimeManager.Instance.DelayCall((int)(timelineDuration - jumpTime) * 1000, () =>
            {
                OnTimelineEnd(null);
            });
        }

        private void OnSkipTimeline(string timelineName)
        {
            //timeline关卡特殊处理
            /*var nextStageConfig = BattleConfigManager.Instance.GetStageConfig(this.stageId, stageSubId + 1);
            if (nextStageConfig == null)
            {
                this.timelineName = null;
                //说明要胜利了
                MissionManager.Instance.OnTimelineComplete();
            }
            else
            {
                BlueprintUtils.StopTimeline(timelineName);
                OnTimelineEnd(null);
            }*/
            OnTimelineEnd(null);
        }

        public void ShowProgressUI(string title,string content,float progress)
        {
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.ShowUIEvent").Action(title,content,progress);
        }
        
        public void UpdateProgressUI(string content,float progress,int type = 0)
        {
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.UpdateUIEvent").Action(content,progress,type);
        }

        public void UpdateFullScreenWarningUI(bool isShow)
        {
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.UpdateFullScreenWarningUI").Action(isShow);
        }
        
        public void UpdateStarUI(int star)
        {
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.UpdateStarUI").Action(star);
        }
        
        public void HideProgressUI()
        {
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.HideUIEvent");
        }

        public Vector3 GetNearestSpawnPoint(float radius,Vector3 centerPosition)
        {
            Vector3 candidate = BattleConstValue.DEFAULT_POINT;
            float minDistance = float.MaxValue;
            Vector3 backupCandidate = BattleConstValue.DEFAULT_POINT;
            float backupDistance = float.MaxValue;
            for(int i = 0; i < spawnPoints.Count; i++)
            {
                var distance = Vector3.Distance(spawnPoints[i],centerPosition);
                if (distance < minDistance && distance >= radius)
                {
                    minDistance = distance;
                    candidate = spawnPoints[i];
                }
                else if (distance < backupDistance)
                {
                    backupDistance = distance;
                    backupCandidate = spawnPoints[i];
                }
            }

            if (candidate == BattleConstValue.DEFAULT_POINT)
            {
                candidate = backupCandidate;
            }
            return candidate;
        }

        private bool isInBossCamera;
        private Transform cachedBossCameraFollow;
        private Vector3 cachedBossCameraForward;
        
        public void ShowBossCamera(Transform transform,Vector3 forward)
        {
            if (isInTimeline)
            {
                return;
            }

            if (!isBattleStart)
            {
                cachedBossCameraFollow = transform;
                cachedBossCameraForward = forward;
                return;
            }
            isInBossCamera = true;
            Pause();
            CameraManager.Instance.SwitchCamera(ECameraType.Boss,transform,forward);
            TimeManager.Instance.DelayCall(5000, () =>
            {
                isInBossCamera = false;
                CameraManager.Instance.SwitchCamera(ECameraType.Follow);
                if (isInTimeline)
                {
                    return;
                }
                Resume();
            });
        }

        public void ShowBossWarning(string nameKey)
        {
            ResidentHandler.Inst.GetFunction("L_SurvivorManager.ShowBossWarning").Action(nameKey,5);
        }

        public void SetIsNight(bool isNight)
        {
            this.isNight = isNight;
            if (isNight)
            {
                if (nightPositionObject == null)
                {
                    nightPositionObject = new GameObject("SetMainCharacterPos");
                    nightPositionObject.AddComponent<SetMainCharacterPos>().idxPos = 0;
                }
            }
            if (TeamGroup != null)
            {
                TeamGroup.SetIsNight(isNight);
                if (nightPositionObject)
                {
                    nightPositionObject.transform.SetParent(TeamGroup.Transform);
                }
            }

            if (DeckManager.Instance.IsInDeck)
            {
                //DeckManager.Instance.SetIsNight(isNight);
                if (nightPositionObject)
                {
                    nightPositionObject.transform.position = DeckManager.Instance.Center;
                }
            }
            RpgNightSettings.RpgNightSettingExtension.NightMode(isNight,1);
            if (isNight)
            {
                if (sceneLight == null)
                {
                    sceneLight = BattlePoolManager.Instance.Get(EBattleResId.SceneLight);
                    sceneLight.Parent = SurvivorManager.Instance.Root;
                }
            }
        }
        private void SetLightDirection(Vector3 direction)
        {
            lightDirection = direction;
            if (HRenderSceneManager.Inst.CurrentBaseRenderScene)
            {
                InitLightDirections();
            }
            ShadowOffset = new Vector4(lightDirection.x, lightDirection.z, 0, 0);
            UnitManager.Instance.UpdateShadowOffset();
            LightController.UpdateForward(BattleConstValue.LightElementMark,direction);
        }
        
        public void InitLightDirections()
        {
            var lights = HRenderSceneManager.Inst.CurrentBaseRenderScene.RenderLights;
            for (int i = 0; i < lights.Count; i++)
            {
                lights[i].transform.forward = lightDirection;
            }
            LightController.UpdateForward(BattleConstValue.LightElementMark,lightDirection);
        }

        private void InitSpawnPoints(List<Vector2> spawnPoints,float gridSize,Vector3 center,Vector3 forward)
        {
            spawnRotation = Quaternion.AngleAxis(PveUtils.GetAngle(forward,Vector3.forward),Vector3.up);
            spawnCenter = center;
            spawnGridSize = gridSize;
            spawnPointGrid.Clear();
            for (int i = 0; i < spawnPoints.Count; i++)
            {
                var point = new Vector3(spawnPoints[i].x, 0, spawnPoints[i].y);
                var grid = BattleHelper.GetGridByPosition(point,center,spawnRotation,gridSize);
                if (!spawnPointGrid.TryGetValue(grid.x, out var dic))
                {
                    dic = new Dictionary<int, Vector3>();
                    spawnPointGrid.Add(grid.x, dic);
                }
                dic[grid.y] = point;
            }
        }

        private List<Vector3> spawnPointCandidate = new List<Vector3>();

        public Vector3 GetSpawnPoint()
        {
            Profiler.BeginSample("GetSpawnPoint");
            spawnPointCandidate.Clear();
            var camera = CameraManager.Instance.MainCamera;
            var forward = camera.transform.forward;
            forward.y = 0;
            var q = Quaternion.AngleAxis(PveUtils.GetAngle(Vector3.forward,forward),Vector3.up);
            var leftTop = BattleHelper.GetGroundPointByScreenPoint(camera,new Vector2(0,Screen.height));
            var rightTop = BattleHelper.GetGroundPointByScreenPoint(camera,new Vector2(Screen.width,Screen.height));
            var bottomRight = BattleHelper.GetGroundPointByScreenPoint(camera,new Vector2(Screen.width,0));
            var leftTopGrid = BattleHelper.GetGridByPosition(leftTop, spawnCenter, spawnRotation, spawnGridSize);
            var rightTopGrid = BattleHelper.GetGridByPosition(rightTop, spawnCenter, spawnRotation, spawnGridSize);
            var rightBottomGrid = BattleHelper.GetGridByPosition(bottomRight, spawnCenter, spawnRotation, spawnGridSize);
            //上
            var left = Mathf.Min(leftTopGrid.x, rightTopGrid.x, rightBottomGrid.x,leftTopGrid.x);
            var right = Mathf.Max(leftTopGrid.x, rightTopGrid.x, rightBottomGrid.x,leftTopGrid.x);
            var top = Mathf.Max(leftTopGrid.y, rightTopGrid.y, rightBottomGrid.y,leftTopGrid.y);
            var bottom = Mathf.Min(leftTopGrid.y, rightTopGrid.y, rightBottomGrid.y,leftTopGrid.y);
            var gridY = top + 1;
            var gridX = 0;
            for (int i = left - 1; i <= right + 1; i++)
            {
                gridX = i;
                CheckSpawnPoint(gridX, gridY);
            }
            //下
            gridY = bottom - 1;
            for (int i = left - 1; i <= right + 1; i++)
            {
                gridX = i;
                CheckSpawnPoint(gridX, gridY);
            }
            //左
            gridX = left - 1;
            for (int i = bottom - 1; i <= top + 1; i++)
            {
                gridY = i;
                CheckSpawnPoint(gridX, gridY);
            }
            //右
            gridX = right + 1;
            for (int i = bottom - 1; i <= top + 1; i++)
            {
                gridY = i;
                CheckSpawnPoint(gridX, gridY);
            }
            Profiler.EndSample();
            if (spawnPointCandidate.Count == 0)
            {
                return BattleHelper.GetRandomPoint(10);
            }
            return spawnPointCandidate[Random.Range(0, spawnPointCandidate.Count)];
        }

        private void CheckSpawnPoint(int gridX, int gridY)
        {
            if (spawnPointGrid.TryGetValue(gridX, out var dic))
            {
                if (dic.TryGetValue(gridY, out var point))
                {
                    spawnPointCandidate.Add(point);
                }
            }
        }

        private void ShowTorch(Vector3 center,Vector3 forward)
        {
            if (sceneTorch == null)
            {
                sceneTorch = BattlePoolManager.Instance.Get(EBattleResId.Torch);
                sceneTorch.Parent = SurvivorManager.Instance.Root;
            }
            sceneTorch.Position = center;
            sceneTorch.Forward = forward;
        }

        private void HideTorch()
        {
            if (sceneTorch != null)
            {
                BattlePoolManager.Instance.Release(sceneTorch);
                sceneTorch = null;
            }
        }

        public void OnAddBoss(BattleUnit bossUnit)
        {
            if (isNight)
            {
                if (nightPositionObjectBoss == null)
                {
                    nightPositionObjectBoss = new GameObject("SetMainCharacterPos");
                    nightPositionObjectBoss.AddComponent<SetMainCharacterPos>().idxPos = 1;
                    nightPositionObjectBoss.transform.SetParent(bossUnit.Transform);
                    nightPositionObjectBoss.transform.localPosition = Vector3.zero;
                }
                RpgNightSettings.RpgNightSettingExtension.NightMode(isNight,2);
            }
        }

        public void ShowBossDeadCamera(BattleUnit bossUnit)
        {
            ChangeTimeScale(0.05f,1,0.2f,1.2f);
            CameraManager.Instance.SwitchCamera(ECameraType.Boss, bossUnit.Transform, default,0.8f);
        }
        
        public override void Dispose()
        {
            startLoadTimelineTime = -1;
            if (timelineName != null)
            {
                BlueprintUtils.StopTimeline(timelineName);
                timelineName = null;
            }
            foreach(var pair in environmentDic)
            {
                ClassManager.Free(pair.Value);
            }

            if (nightPositionObjectBoss != null)
            {
                GameObject.DestroyImmediate(nightPositionObjectBoss);
                nightPositionObjectBoss = null;
            }
            
            if (nightPositionObject)
            {
                GameObject.DestroyImmediate(nightPositionObject);
                nightPositionObject = null;
            }

            HideTorch();
            environmentDic.Clear();
            environmentUnit?.Dispose();
            environmentUnit = null;
            if (sceneLight != null)
            {
                BattlePoolManager.Instance.Release(sceneLight);
                sceneLight = null;
            }
            TeamGroup?.Dispose();
            TeamGroup = null;
            if (mapData)
            {
                GameObject.Destroy(mapData.gameObject);
            }
            mapData = null;
            monsterGroupDic.Clear();
            mapPointDic.Clear();
            regionDic.Clear();
            interactableDic.Clear();
            routeDic.Clear();
            truchPathDic.Clear();
            spawnPointGrid.Clear();
            fogGroup = null;
            stageConfig = null;
            stageConfigs = null;
            cachedBossCameraFollow = null;
            IsPause = false;
            fogMask = 0;
            audioState = EAudioState.Common;
            Yoozoo.Gameplay.Liberty.Nodes.PlayTimeline.SkipTimeline -= OnSkipTimeline;
            Yoozoo.Gameplay.Liberty.Nodes.PlayTimeline.JumpTimeline -= OnJumpTimeline;
            RpgNightSettings.RpgNightSettingExtension.NightMode(false);
        }
    }
}
